<?php

namespace App\Http\Middleware;

use App\EmptyObject;
use App\Models\Action;
use App\Models\Group;
use App\Models\Project;
use App\Models\Role;
use App\Models\User;
use App\Models\WxClient;
use App\Plugins\PluginInfo;
use App\Services\HelpService;
use Closure;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Pagination\LengthAwarePaginator;

class Links
{
    const ROUTE = [
        'users' => 'user',
        'groups' => 'group',
        'roles' => 'role',
        'projects' => 'project',
        'customers' => 'customer',
    ];
    const METHOD = ['GET', 'PATCH', 'PUT', 'POST'];
    private $__route;
    private $__isAdmin;
    private $__user;
    private $__data;
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $result = $next($request);
        $status = intval($result->status());
        if ($status !== 200) {
            return $result;
        } else {
            $content = $result->getOriginalContent();
        }
        $route = $request->segment(2);
        if (HelpService::fromApp() || empty(self::ROUTE[$route])
            || !in_array($request->method(), self::METHOD)) {
            return $result;
        }
        $this->__route = self::ROUTE[$route];
        $this->__user = $request->user();
        $tran_content =  [];
        if ($content instanceof LengthAwarePaginator) {
            $tran_content = new Collection();
            foreach ($content as $value) {
                $this->__data = $value;
                $this->__data['links'] = $this->addLinks($request);
                $tran_content->add($this->__data);
            }
            $tran_content = new LengthAwarePaginator($tran_content,
                $content->total(), 20, request()->input('page', 1));
        } else if (isset($content['total'])) {
            $temp = [];
            foreach ($content['data'] as $value) {
                $this->__data = $value;
                $this->__data['links'] = $this->addLinks($request);
                array_push($temp, $this->__data);
            }
            $tran_content['data'] = $temp;
            $tran_content['total'] = $content['total'];
        } else if ($this->__route === 'group') {
            $tran_content = $this->tree($request, $content);
        } else if (is_string($content)){
            return $result;
        } else {
            $this->__data = $content;
            $this->__data['links'] = $this->addLinks($request);
            $tran_content = $this->__data;
        }
        $result->setContent($tran_content);
        return $result;
    }

    public function addLinks($request) {
        $role = Role::find($this->__user->role_id);
        if (is_null($role)) {
            return null;
        }
        $isAdmin = false;
        if ($role->actions === []) {
            $actions_key = Action::all()->pluck('key')->all();
            $isAdmin = true;
        } else {
            $actions_key = $role->actions;
        }
        $actions = Action::where([
            'key' => ['$in' => $actions_key],
            'group' => $this->__route
        ])->get();
        if ($actions->count() === 0) {
            return null;
        }
        if (!isset($this->__data['_id']) && $this->__route !== 'project') {
            return [];
        }
        $function = $this->__route;
        return $this->$function($actions);
    }

    public function role($actions) {
        $result = [];
        $show_links = ['role.edit'];
        if ($this->__isAdmin
            || $this->__user->role_id === $this->__data['_id']) {
            return [];
        }
        $user_count = User::where('role_id', $this->__data['_id'])->count();
        if ($user_count === 0) {
            array_push($show_links, 'role.destroy');
        }
        return $this->getEnableActions($show_links, $actions);
    }

    public function user($actions) {
        $show_links = ['user.edit'];
        if ($this->__data['status']) {
            array_push($show_links, 'user.disable');
        } else {
            array_push($show_links, 'user.enable');
        }
        return $this->getEnableActions($show_links, $actions);
    }

    public function group($actions) {
        $show_links = [];
        $hasUser = User::where('group_id', $this->__data['_id'])->count();
        $hasChildren = isset($this->__data['children'])
            && !empty($this->__data['children']);
        $project = Project::where('group_id', $this->__data['_id'])->first();
        if ($this->__data['_id'] === $this->__user['group_id']) {
            if (!$project) {
                array_push($show_links, 'group.addChild');
                return $this->getEnableActions($show_links, $actions);
            } else {
                return $this->getEnableActions($show_links, $actions);
            }
        } else {
            array_push($show_links, 'group.edit');
        }
        if (!$hasUser && !$hasChildren
            && ((!is_null($project) && $project['wx_id'] === [])
            || is_null($project))) {
            array_push($show_links, 'group.destroy');
        }
        if (is_null($project)) {
            array_push($show_links, 'group.addChild');
        }
        return $this->getEnableActions($show_links, $actions);
    }

    public function project($actions) {
        $show_links = [];
        if (!isset($this->__data['wxClients'])) {
            return [];
        }
        if (($this->__data['wxClients'] InstanceOf Collection
                || is_array($this->__data['wxClients']))
            && count($this->__data['wxClients'])) {
            foreach ($this->__data['wxClients'] as $wxClient) {
                if ($wxClient['friendCount'] === 0) {
                    array_push($show_links, 'project.delWx');
                }
            }
            if (count($show_links) === 0) {
                array_push($show_links, 'project.addWx');
            }
        } else {
            array_push($show_links, 'project.addWx');
        }
        if (PluginInfo::getInstance()->getPlugin()
            && ($this->__data['plugins'] instanceof EmptyObject
                || empty($this->__data['plugins'][PluginInfo::getInstance()->getName()]))
            && $this->__data['_id'] !== null) {
            array_push($show_links, 'project.addData');
        }
        return $this->getEnableActions($show_links, $actions);
    }

    public function customer($actions) {
        $show_links = ['customer.move', 'customer.edit'];
        return $this->getEnableActions($show_links, $actions);
    }

    public function tree($request, $group) {
        $this->__data = $group;
        if($group && isset($group['_id']) ) {
            $group['links'] = $this->addLinks($request);
            if (!empty($group['children'])) {
                foreach ($group['children'] as $key => $children) {
                    if (isset($children['_id'])) {
                        $group['children'][$key] = $this->tree($request, $children);
                    }
                }
            }
        }
        return $group;
    }

    public function getEnableActions($show_links, $actions) {
        $result = [];
        foreach ($actions as $action) {
            if (in_array($action['key'], $show_links)) {
                $action['uri'] =
                    str_replace('{'.$this->__route.'_id}',
                        $this->__data['_id'], $action['uri']);
                array_push($result, $action);
            }
        }
        return $result;
    }
}
